package com.springcloud.common;

import com.springcloud.AuthFilter;
import com.springcloud.filter.TimerFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 路径映射
 *
 * @author: 顾志杰
 */
@Configuration
@Slf4j
public class GatewayConfiguration implements ApplicationEventPublisherAware {

  @Autowired
  private TimerFilter timerFilter;

//  @Autowired
//  private AuthFilter authFilter;

  private ApplicationEventPublisher publisher;

  @Autowired
  private RouteDefinitionWriter routeDefinitionWriter;

  @Autowired
  private GatewayDao gatewayDao;

  @Override
  public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    this.publisher = applicationEventPublisher;
  }

  public String loadRoute(GateWay gateWay) {
    /*路由配置*/
    RouteDefinition definition = new RouteDefinition();
    /*断言配置*/
    Map<String, String> predicateParams = new HashMap<>(8);
    PredicateDefinition predicate = new PredicateDefinition();
    /*过滤器配置*/
    FilterDefinition filter = new FilterDefinition();
    Map<String, String> filterParams = new HashMap<>(8);

    URI uri = null;
    if ("0".equals(gateWay.getRouteType())) {
      /*如果配置路由type为0的话 则从数据库中获取服务地址*/
      uri = UriComponentsBuilder.fromUriString(gateWay.getRouteUrl()).build().toUri();
    } else {
      uri = UriComponentsBuilder.fromHttpUrl(gateWay.getRouteUrl()).build().toUri();
    }
    /*定义的路由唯一的id*/
    definition.setId(gateWay.getRouteId());
    predicate.setName("Path");
    /*断言匹配位置*/
    predicateParams.put("pattern", gateWay.getRoutePattern());
    predicate.setArgs(predicateParams);

    /*名称是固定的, 路径去前缀*/
    filter.setName("StripPrefix");
    filterParams.put("_genkey_0", "1");
    filter.setArgs(filterParams);
    definition.setPredicates(Arrays.asList(predicate));
    definition.setFilters(Arrays.asList(filter));
    definition.setUri(uri);
    routeDefinitionWriter.save(Mono.just(definition)).subscribe();
    this.publisher.publishEvent(new RefreshRoutesEvent(this));

    return "success";

  }
//  @Bean
//  @Order
  public RouteLocator customizedRoutes(RouteLocatorBuilder builder) {
    return builder.routes()
      /*匹配断言 导向正确的uri*/
      .route(r -> r.path("/java/**")
        .and().method(HttpMethod.GET)
        .and().header("name")
        /*更改请求中的参数*/
        .filters(f -> f.stripPrefix(1)
          .addResponseHeader("java-param", "geteway-config")
          .filter(timerFilter)
//          .filter(authFilter)
        )
        .uri("lb://FEIGN-CLIENT")
      )
      .route(r -> r.path("/seckill/**")
        /* 服务启动后 往后推迟1分钟生效 */
        .and().after(ZonedDateTime.now().plusMinutes(1))
        .filters(f -> f.stripPrefix(1))
        .uri("lb://FEIGN-CLIENT")
      )
      .build();
  }

  @Bean
  @Order
  public String loadRouteDefinition() throws Exception {
    List<GateWay> gateWayEntities = gatewayDao.findAll();
    for (GateWay gb : gateWayEntities) {
      loadRoute(gb);
    }
    log.info("网关路由数据初始化成功！网关数量:{}",gateWayEntities.size());
    return "网关路由数据初始化成功！";
  }

}
